<?php

namespace app\common\service;

use app\common\exception\MiException;
use app\common\service\pay\WxpayService;
use app\common\service\traits\InstanceTrait;
use app\model\site\User;
use app\model\site\UserBalanceLog;
use app\model\store\DistRewardLog;
use app\model\store\Order;
use app\model\store\OrderItem;
use app\model\store\OrderRefund;
use app\site\service\SiteAuthService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;

class CommonOrderRefundService
{

    use InstanceTrait;

    /***
     * 退款
     * @param OrderRefund $refund
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws MiException
     * @throws ModelNotFoundException
     */
    function refundAction(OrderRefund $refund): bool
    {
        $siteId = $refund->site_id;
        $uid = $refund->user_id;
        $config = CommonSiteConfigService::instance()->getWxPayConfig($siteId);
        $order = Order::find($refund->order_id);
        if (!$order) throw new MiException("订单不存在，无法退款");
        $payType = $order->pay_type;
        if ($payType == 'wx'){
            $notify = request()->domain() . '/common/public/wxRefundNotify/id/'.$siteId;
            $data = [
                'transaction_id' => $order->pay_order_no,
                'out_refund_no'  => $refund->order_refund_no,
                'notify_url' => $notify,
                'amount'         => [
                    'refund'   => (int)($refund->refund_price*100),
                    'total'    => (int)($order->pay_price*100),
                    'currency' => 'CNY',
                ],
            ];
            // 请求微信退款
            WxpayService::getInstance($config)->refunds($data);
            // 会在异步回调中执行退款成功的操作，这里不做处理

        }elseif ($payType == 'balance'){
            $amount = $refund->refund_price;
            // 回退余额
            User::where('id', $uid)->inc('balance', $amount)->update();
            // 创建余额记录
            UserBalanceLog::create([
                'site_id' => $siteId,
                'user_id' => $uid,
                'amount' => $amount,
                'rel_model' => 'order',
                'rel_id' => $order->id,
                'change_type' => 4,
                'note' => '订单退款',
            ]);
            // 直接执行退款成功的操作
            $this->refundSuccess($refund);
        }

        return true;
    }

    /**
     * 退款单退款成功后的操作逻辑
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws MiException
     */
    public function refundSuccess(OrderRefund $refund, $params=''){
        // 如果退款单的状态是未退款，修改订单状态为已退款
        $refund->refund_status = 1;
        if ($params){
            $refund->out_refund_no = $params['refund_id']; // 微信退款单号
        }
        $refund->save();
        // 退款金额
        $refundPrice = $refund->refund_price;

        $order = Order::find($refund->order_id);
        if ($order){
            $orp = $order->refund_price;
            $order->refund_price = $orp + $refundPrice;    // 修改订单的已退款金额
            $order->save();
            // 判断订单是否全部退款
            $totalRefundNum = OrderRefund::where('order_id', $order->id)->where('refund_status',1)->sum('num');
            if ($totalRefundNum == $order->num){    // 订单已全部退款，关闭订单
                CommonOrderService::instance()->close($order->id, 'refund');
            }

            // 扣除冻结中的佣金中的被退款的金额
            $rewards = DistRewardLog::where('rel_model', 'order')->where('rel_id', $order->id)->where('status', 0)->select();
            // 因为计算佣金使用的是商品原价，这里要获取订单商品中的原价
            $orderItem = OrderItem::where('id', $refund->order_item_id)->find();
            $oiPrice = $orderItem->total_price;
            foreach ($rewards as $rew){
                $rew->price -= $oiPrice;
                $rew->amount = max(0, $rew->amount - round($oiPrice*$rew->rate,2));
                $rew->save();
            }
        }
    }

}
